using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;

using System.Drawing;
using System.Windows.Forms;

using Athena.Objects;
using Athena.Core;
using Athena.Plugins;

namespace Athena.Tools
{
    public class MakeModuleTool : INonVisualTool
    {
        System.Windows.Forms.OpenFileDialog openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
        System.Windows.Forms.SaveFileDialog saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();

        public override bool Handles(List<Type> oTypes)
        {
            bool bResult = true;
            foreach (Type t in oTypes)
            {
                bResult &= Handles(t);
                if (!bResult) return false;
            }
            return bResult;
        }

        private bool Handles(Type t)
        {
            return Utility.IsTypeNoAbstract(typeof(Athena.Objects.IDrawable), t);
        }
        
        /// <summary>
        /// Handles Ctrl+M for making new module
        /// </summary>
        /// <param name="args"></param>
        public override void OnKeyDown(KeyEventArgs args)
        {
            if (args.KeyCode == Keys.M && args.Control)
            {
                if (CurrentModel.Selected.Count > 0)
                {
                    HistoryManager.History.SetControllPoint("Made new Module");
                    MakeModule(CurrentModel.Selected);
                    Utility.Refresh();
                    args.Handled = true;
                }
            }
        }

        class ToolCommand
        {
            private string _sCommand;

            public string Command
            {
                get { return _sCommand; }
                set { _sCommand = value; }
            }

            private Bitmap _Icon;
            public Bitmap Icon
            {
                get
                {
                    return _Icon;
                }
                set
                {
                    _Icon = value;
                }
            }

            private string _Description;
            public string Description
            {
                get
                {
                    return _Description;
                }
                set
                {
                    _Description = value;
                }
            }


            public ToolCommand()
            {
                _sCommand = "-";
                _Icon = null;
            }

            /// <summary>
            /// Initializes a new instance of the ToolCommand class.
            /// </summary>
            /// <param name="sCommand"></param>
            /// <param name="icon"></param>
            /// <param name="description"></param>
            public ToolCommand(string sCommand, Bitmap icon, string description)
            {
                _sCommand = sCommand;
                _Icon = icon;
                _Description = description;
            }

            public ToolStripItem ToMenuItem()
            {
                if (_Icon == null && _sCommand == null)
                {
                    return new ToolStripSeparator();
                }
                else
                {
                    ToolStripMenuItem oItem = new ToolStripMenuItem(_sCommand, _Icon);
                    oItem.Tag = _sCommand;
                    oItem.ToolTipText = _Description;
                    oItem.ImageScaling = ToolStripItemImageScaling.None;
                    oItem.Click += new EventHandler(CommandExecute);
                    return oItem;
                }
            }

            public ToolStripItem ToToolStripButton()
            {
                if (_Icon == null)
                {
                    return new ToolStripSeparator();
                }
                else
                {
                    ToolStripButton oButton = new ToolStripButton(_sCommand, _Icon);
                    oButton.DisplayStyle = ToolStripItemDisplayStyle.Image;
                    oButton.Tag = _sCommand;
                    oButton.ImageScaling = ToolStripItemImageScaling.None;
                    oButton.ToolTipText = _Description;
                    oButton.Click += new EventHandler(CommandExecute);
                    return oButton;
                }
            }

            void CommandExecute(object sender, EventArgs e)
            {
                string sTag = "";
                if (sender is ToolStripButton)
                    sTag = (string)((ToolStripButton)sender).Tag;
                else if (sender is ToolStripMenuItem)
                    sTag = (string)((ToolStripMenuItem)sender).Tag;
                else
                    return;
                switch (sTag)
                {
                    case "Link Item":
                        if (CurrentModel.Selected.Count > 0)
                        {
                            HistoryManager.History.SetControllPoint("Made new link");
                        }

                        break;
                    case "Make new Module (Ctrl+M)":                        
                        if (CurrentModel.Selected.Count > 0)
                        {
                            HistoryManager.History.SetControllPoint("Made new Module");
                            MakeModule(CurrentModel.Selected);
                            Utility.Refresh();
                        }
                        break;
                    case "Encapsulate":
                        if (CurrentModel.Selected.Count > 0)
                        {
                            HistoryManager.History.SetControllPoint("Module(s) encapsulated");
                            foreach (IDrawable id in CurrentModel.Selected)
                            {
                                if (id is ModuleGlyph)
                                    ((ModuleGlyph)id).Encapsulate = !((ModuleGlyph)id).Encapsulate;
                            }
                            Utility.Refresh();
                        }
                        break;
                    
                    case "Save Module":
                        //HistoryManager.History.SetControllPoint("Save Module");                        

                        if (Instance.saveFileDialog1.ShowDialog() == DialogResult.OK)
                        {
                            string sFileName = Instance.saveFileDialog1.FileName;

                            FileInfo oInfo = new FileInfo(sFileName);

                            switch (oInfo.Extension.ToUpper())
                            {
                                case ".TXT":
                                case "TXT":
                                    {
                                        if (CurrentModel.Selected.Count > 0 && CurrentModel.Selected[0].Item is Module)
                                        {
                                            StreamWriter oStream = new StreamWriter(new FileStream(sFileName, FileMode.Create));
                                            try
                                            {
                                                IO.ModuleReaderWriter.WriteModule(CurrentModel.Selected[0].Item as Module, oStream);
                                            }
                                            catch (Exception) { }
                                            oStream.Close();
                                            oStream.Dispose();
                                        }
                                    }
                                    break;
                                case ".JAN":
                                case "JAN":
                                    {
                                        if (CurrentModel.Selected.Count > 0 && CurrentModel.Selected[0].Item is Module)
                                        {
                                            FileStream oStream = new FileStream(sFileName, FileMode.Create);
                                            try
                                            {
                                                IO.JarnacWriter oWriter = new Athena.IO.JarnacWriter(oStream);
                                                oWriter.WriteModule(oStream, (Module)CurrentModel.Selected[0].Item);
                                            }
                                            catch (Exception) { }
                                            oStream.Close();
                                            oStream.Dispose();
                                        }
                                    }
                                    break;
                                default:
                                    List<IDrawable> modules = new List<IDrawable>();

                                    foreach (IDrawable id in CurrentModel.Selected)
                                        if (!id.NullItem && id.Item is Module)
                                            modules.Add(id);


                                    if (modules.Count > 1)
                                    {
                                        CurrentModel.SaveModel(sFileName);
                                    }
                                    else
                                    {
                                        if (modules.Count == 1)
                                        {
                                            FileStream oStream = new FileStream(sFileName, FileMode.Create);
                                            try
                                            {
                                                Model model = new Model();
                                                model.AddToModel(modules[0], false, false, false, false);
                                                IO.XMLWriter.WriteModel(oStream, model, false);
                                                CurrentModel.AddToModel(modules[0], false, false, false, false);
                                            }
                                            catch (Exception) { }
                                            oStream.Close();
                                            oStream.Dispose();
                                        }
                                    }
                                    break;
                            }
                        }
                        break;
                    case "Load Module":
                        if (Instance.openFileDialog1.ShowDialog() == DialogResult.OK)
                        {
                            string sFileName = Instance.openFileDialog1.FileName;
                            HistoryManager.History.SetControllPoint("Module loaded");

                            XmlTextReader xmlReader = new XmlTextReader(sFileName);
                            try
                            {
                                Core.Item item = IO.XMLReader.ReadItem(xmlReader, null);
                                Module module = item as Module;

                                if (module != null)
                                {

                                    if (module.Drawable == null)
                                        module.GenerateDrawable(new PointF());

                                    CurrentModel.AddToModel(module.Drawable);

                                    Utility.Refresh();
                                }
                            }
                            catch (Exception) { }

                            xmlReader.Close();
                        }
                        break;
                    default:
                        break;
                }
            }
        }
        /// <summary>
        /// The chief function in this class. Given a list of items, this function constructs a new PartGlyph 
        /// and a Module that contains all those items. The Parts' input/output are adjusted. PartGlyph automatically
        /// sets the Linking points
        /// </summary>
        /// <param name="listOfItems"></param>
        public static void MakeModule(List<IDrawable> listOfItems)
        {
            /*******get the bounding box around all the IGlyph*******/
            PointF minLocation = new PointF(0,0), maxLocation = new PointF(0,0);
            bool valid = false;
            foreach (IDrawable id in listOfItems)
            {
                valid = true;   //must have at least one non-connector
                if (minLocation.X == 0 && maxLocation.X == 0)
                {
                    minLocation = maxLocation = id.Location;
                }
                if (id.Location.X < minLocation.X) minLocation.X = id.Location.X;
                if (id.Location.Y < minLocation.Y) minLocation.Y = id.Location.Y;
                if (id.Bounds.Right > maxLocation.X) maxLocation.X = id.Bounds.Right;
                if (id.Bounds.Bottom > maxLocation.Y) maxLocation.Y = id.Bounds.Bottom;
            }

            minLocation.X -= 10;
            minLocation.Y -= 10;
            maxLocation.X += 50;
            maxLocation.Y += 50;
            if (!valid) return;

            /******found the bounding box*******/

            ModuleGlyph newModule = new ModuleGlyph(minLocation);
            newModule.Dimensions = new SizeF(maxLocation.X - minLocation.X, maxLocation.Y - minLocation.Y);
            CurrentModel.AddToModel(newModule);
            newModule.DoneModifying(Corner.None,true);
            //MakeIO(newModule);
        }


        static ToolCommand[] _oCommands = new ToolCommand[]
        {
            new ToolCommand("Make new Module (Ctrl+M)",  new Bitmap(20,20), "Makes a new module from selected items"),
            new ToolCommand("Encapsulate", new Bitmap(20,20), "Hides all the internal components of a module"),            
            new ToolCommand("Save Module", new Bitmap(20,20), "Save this module to a file"),
            new ToolCommand("Load Module", new Bitmap(20,20), "Load module from a file")            
        };

        private static MakeModuleTool _oInstance = new MakeModuleTool();
        public static MakeModuleTool Instance
        {
            get { return _oInstance; }
        }

        public void MakeClick(object sender, EventArgs e)
        {
            if (CurrentModel.Selected.Count > 0)
            {
                try
                {
                    HistoryManager.History.SetControllPoint("Made new module");
                    MakeModule(CurrentModel.Selected);
                }
                catch (Exception)
                {
                    Utility.SetMessage("Make module failed");
                }
            }
            else
                Utility.SetMessage("Please Select one or more Items to make the module");
        }

        private MakeModuleTool()
        {
            // no items to put into global tool window
            _bHasMenuItems = false;
            // has items to put into context menu
            _bHasContextMenuItems = true;
            // needs a separate toolstrip for the arrange actions            
            _bRequiresNewToolWindow = true;

            // register with main instance
            ToolManager.Instance.RegisterTool("Module Tool", "Makes a new modules from selected items", this);

            // 
            // openFileDialog1
            // 
            this.openFileDialog1.DefaultExt = "txt";
            this.openFileDialog1.DefaultExt = "axml";
            this.openFileDialog1.Filter = "All supported files|*.axml;*.txt|Athena filles|*.axml|" +
                                        "Module Description file|*.txt|All files|*.*";
            this.openFileDialog1.Title = "Open a Model";
            // 
            // saveFileDialog1
            // 
            this.saveFileDialog1.DefaultExt = "axml";
            this.saveFileDialog1.Filter = "All supported files|*.axml;*.jan;*.txt|Athena filles|*.axml|" +
                                          "Jarnac files|*.jan|Module Description file|*.txt|All files|*.*";
            this.saveFileDialog1.Title = "Save the Model";            
        }

        public override ToolManager.Order Order
        {
            get
            {
                return ToolManager.Order.FRONT;
            }
        }

        public override void SetupToolStrip(ToolStrip oStrip)
        {
            /*
            foreach (ToolCommand command in _oCommands)
            {
                oStrip.Items.Add(command.ToToolStripButton());
            }*/

            ToolStripButton oButton = new ToolStripButton();
            oButton.Text = "Make Module";
            oButton.ToolTipText = "Make the selected Items into a Module (Ctrl+M)";
            oButton.Click += new EventHandler(MakeClick);
            oStrip.Items.Add(oButton);
        }
        public override void SetupContextMenu(ToolStripMenuItem oStrip)
        {
            foreach (ToolCommand command in _oCommands)
            {
                oStrip.DropDownItems.Add(command.ToMenuItem());
            }
        }

    }
}
